package com.unitd.frame.mybatis.kit;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @desc 缓存对象的反射工具类
 * @filename ReflectKit.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2017/2/6
 */
public class ReflectKit {

	private static final String TYPE_CLASS_NAME_PREFIX = "class ";
	private static final String TYPE_INTERFACE_NAME_PREFIX = "interface ";

	private ReflectKit() {
	}

	/**
	 * @desc 获取某个指定对象的指定属性的值
	 * @param target       指定的对象
	 * @param propertyName 指定对象的属性
	 * @return 属性的值
	 */
	public static Object getObjectValue(Object target, String propertyName) {
		try {
			PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, target.getClass());
			return descriptor.getReadMethod().invoke(target);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @desc 根据class类型及名称获取对应的实际的class的名称
	 * @param type class类型
	 * @return 类名
	 */
	public static String getClassName(Type type) {
		if (type == null) {
			return "";
		}
		String className = type.toString();
		if (className.startsWith(TYPE_CLASS_NAME_PREFIX)) {
			className = className.substring(TYPE_CLASS_NAME_PREFIX.length());
		} else if (className.startsWith(TYPE_INTERFACE_NAME_PREFIX)) {
			className = className.substring(TYPE_INTERFACE_NAME_PREFIX.length());
		}
		return className;
	}

	/**
	 * @desc 根据class类型及名称获取对应的实际的class
	 * @param type class类型
	 * @return Class
	 */
	public static Class<?> getClass(Type type)
			throws ClassNotFoundException {
		String className = getClassName(type);
		if (className == null || className.isEmpty()) {
			return null;
		}
		return Class.forName(className);
	}


	/**
	 * @desc 根据指定的class类型, 获取该类的实例对象
	 * @param type class类型
	 * @return Object
	 */
	public static Object newInstance(Type type)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		Class<?> clazz = getClass(type);
		if (clazz == null) {
			return null;
		}
		return clazz.newInstance();
	}

	public static Type[] getClassGenericTypes(Class<?> clazz) {
		Type superclassType = clazz.getGenericSuperclass();
		if (superclassType != null) {
			if (!ParameterizedType.class.isAssignableFrom(superclassType.getClass())) {
				return null;
			}
			return ((ParameterizedType) superclassType).getActualTypeArguments();
		}
		return null;
	}

	public static boolean hasDefaultConstructor(Class<?> clazz) throws SecurityException {
		Class<?>[] empty = {};
		try {
			clazz.getConstructor(empty);
		} catch (NoSuchMethodException e) {
			return false;
		}
		return true;
	}

	public static Class<?> getFieldClass(Class<?> clazz, String name) {
		if (clazz == null || name == null || name.isEmpty()) {
			return null;
		}

		Class<?> propertyClass = null;

		for (Field field : clazz.getDeclaredFields()) {
			field.setAccessible(true);
			if (field.getName().equalsIgnoreCase(name)) {
				propertyClass = field.getType();
				break;
			}
		}

		return propertyClass;
	}

	public static Class<?> getMethodReturnType(Class<?> clazz, String name) {
		if (clazz == null || name == null || name.isEmpty()) {
			return null;
		}

		name = name.toLowerCase();
		Class<?> returnType = null;

		for (Method method : clazz.getDeclaredMethods()) {
			if (method.getName().equals(name)) {
				returnType = method.getReturnType();
				break;
			}
		}

		return returnType;
	}

	@SuppressWarnings({"unchecked", "rawtypes"})
	public static Object getEnumConstant(Class<?> clazz, String name) {
		if (clazz == null || name == null || name.isEmpty()) {
			return null;
		}
		return Enum.valueOf((Class<Enum>) clazz, name);
	}
}